#include "stdafx.h"
#include "vol_user_app_info.h"

void CVolRedisWraper::Close()
{
	if (pContext)
	{
		redisFree(pContext);
		pContext = NULL;
	}
}

void CVolRedisWraper::Connect(const char * ip, int port, const CVolString& password, unsigned int dbid, int timeout)
{
	if (pContext == NULL)
	{
		struct timeval tv = {timeout, 0};
		pContext = redisConnectWithTimeout(ip, port, tv);
		
		if (!password.IsEmpty() && pContext != NULL)	//携带AUTH密码?
		{
			CVolString tempPassword = password;
			tempPassword.InsertText(0, _T("AUTH "));
			redisReply* authRet = ExcCommand(GetMbsText(tempPassword, CVolMem(), NULL));
			if (authRet) freeReplyObject (authRet);
		}
		
		if (dbid > 0)	//非默认库号?
		{
			char buf[64];
			snprintf(buf, 64, "SELECT %d", dbid);
			redisReply* authRet = ExcCommand(buf);
			if (authRet) freeReplyObject (authRet);
		}
	}
}

redisReply* CVolRedisWraper::ExcCommand(const char *cmd)
{
	if (pContext != NULL)
		return (redisReply*)redisCommand(pContext, cmd);
	return NULL;
}

#define DECLARE_REDIS_EXCCOMMAND_EXTEND_PARAM(return_value, call)  					\
	if (pContext != NULL)															\
	{																				\
		va_list argList;															\
        va_start(argList, cmd);														\
		const INT_P npNumParams = _tcslen (szParamTypes);							\
		ASSERT (npNumParams >= 1);													\
		CMIntArray arynOffset;														\
		arynOffset.Add(0);															\
		CVolMem memData;															\
		memData.Append(cmd, strlen(cmd));											\
		for (INT_P npParamIndex = 1; npParamIndex < npNumParams; npParamIndex++)	\
		{																			\
			arynOffset.Add ((INT)memData.GetSize ());								\
			switch (szParamTypes [npParamIndex])									\
			{																		\
				case _C_VOL_SBYTE:													\
					memData.AddByte(va_arg (argList, S_BYTE));						\
					break;															\
				case _C_VOL_SHORT:													\
					memData.AddWord((WORD)va_arg (argList, SHORT));					\
					break;															\
				case _C_VOL_WCHAR:													\
					memData.AddChar(va_arg (argList, TCHAR));						\
					break;															\
				case _C_VOL_INT:													\
					memData.AddInt(va_arg (argList, INT));							\
					break;															\
				case _C_VOL_VINT:													\
					memData.AddIntP(va_arg (argList, INT_P));						\
					break;															\
				case _C_VOL_LONG:													\
					memData.AddInt64(va_arg (argList, INT64));						\
					break;															\
				case _C_VOL_FLOAT:													\
					memData.AddFloat((FLOAT)va_arg (argList, DOUBLE));				\
					break;															\
				case _C_VOL_DOUBLE:													\
					memData.AddDouble(va_arg (argList, DOUBLE));					\
					break;															\
				case _C_VOL_BOOL:													\
					memData.AddBool(va_arg (argList, BOOL));						\
					break;															\
				case _C_VOL_STRING:													\
				{																	\
					CVolMem mbsBuf;													\
					INT_P npLen = 0;												\
					const char* mbsText = GetMbsText(va_arg (argList, const TCHAR*), mbsBuf, &npLen);	\
					memData.Append(mbsText, npLen * sizeof (char));					\
					break; 	}														\
				default:  {  														\
					ASSERT (szParamTypes [npParamIndex] == _C_VOL_CLASS);			\
					CVolObject* pObject = va_arg (argList, CVolObject*);			\
					if (P_IS_VOL_INSTANCE_OF (pObject, CVolMem) == FALSE)			\
						return return_value;										\
					memData.Append (((CVolMem*)pObject)->GetPtr (), ((CVolMem*)pObject)->GetSize ());	\
					break;  }														\
			}																		\
		}																			\
		va_end(argList);															\
		INT_P npCount = arynOffset.GetCount();										\
		arynOffset.Add ((INT)memData.GetSize ());									\
		char** argv = new char*[npCount];											\
		size_t* argvlen = new size_t[npCount];										\
		char* pData = (char*)memData.GetPtr();										\
		for (INT_P argIndex = 0; argIndex < npCount; argIndex++)					\
		{																			\
			INT nOffset = arynOffset.GetAt (argIndex);								\
			argv[argIndex] = pData + nOffset;										\
			argvlen[argIndex] = arynOffset.GetAt (argIndex + 1) - nOffset;			\
		}																			\
		call;																		\
		delete[] argv;																\
		delete[] argvlen;															\
		return ret;																	\
	}																				\
	return return_value;
		
redisReply* CVolRedisWraper::ExcCommandExtend(const TCHAR* szParamTypes, const char *cmd, ...)
{
	DECLARE_REDIS_EXCCOMMAND_EXTEND_PARAM(NULL, redisReply* ret = (redisReply*)redisCommandArgv(pContext, (INT)npCount, (const char**)argv, argvlen))
}

BOOL CVolRedisWraper::AppendCommand(const char *cmd)
{
	if (pContext != NULL)
		return redisAppendCommand(pContext, cmd) == REDIS_OK;
	return FALSE;
}

BOOL CVolRedisWraper::AppendCommandExtend(const TCHAR* szParamTypes, const char *cmd, ...)
{
	DECLARE_REDIS_EXCCOMMAND_EXTEND_PARAM(FALSE, BOOL ret = redisAppendCommandArgv(pContext, (INT)npCount, (const char**)argv, argvlen) == REDIS_OK)
}

redisReply* CVolRedisWraper::GetExcReply()
{
	if (pContext != NULL)
	{
		redisReply* pReply;
		return redisGetReply(pContext, (void**)&pReply) == REDIS_OK ? pReply : NULL;
	}
	return NULL;
}